home *** CD-ROM | disk | FTP | other *** search
/ The Best of MacTutor - S…e Code for Volumes 1 to 5 / The Best of MacTutor - Source Code for Volume 1-5 (Wayzata Technology)(6031)(1990).bin / Source Code / #40 (Jan 89) / FinderControls / CDEF texte < prev    next >
Text File  |  1988-04-26  |  18KB  |  650 lines

  1. {**********************************************}
  2. { Put this file in the CDEF Project after DAPasLib, MacTraps, ROM85lib and ROM85. }
  3. { Don't forget to "Use resource file" in "Run options" of menu "Project". }
  4. { This resource file must contain the WIND ,CNTL, MENU, ICN#, ICON, MDEF }
  5. { resources that the Shell Project needs together with the compiled CDEF resource. }
  6.  
  7. { "Build and save as…" resource code of type CDEF and ID 128 in file "CDEF code" }
  8. {**********************************************}
  9. UNIT CDEF;
  10.  
  11. INTERFACE
  12.  
  13.     USES
  14.         ROM85;
  15.  
  16.     FUNCTION Main (varCode : integer;
  17.                                     theControl : ControlHandle;
  18.                                     message : integer;
  19.                                     param : longint) : longint;
  20.  
  21. IMPLEMENTATION
  22.  
  23.     CONST
  24.         RestState = 0;
  25.         SelectState = 1;
  26.         OpenState = 2;
  27.         SelectOpenState = 3;
  28.         ThrownAwayState = 4;
  29.         MenuReturnState = 5;
  30.  
  31.         movableBit = 1;
  32.         doubleClickableBit = 2;
  33.         trashBit = 3;
  34.         menuBit = 4;
  35.         varCodeBase = 200;        { bit-offset of end of varCode in ControlRecord }
  36.         integerLength = 16;
  37.  
  38.     TYPE
  39.         DataHandle = ^DataPointer;
  40.         DataPointer = ^DataRecord;
  41.         DataRecord = RECORD
  42.                 theIcon : handle;
  43.                 theMenu : MenuHandle;
  44.             END;
  45.  
  46.     FUNCTION PopUpMenuSelect (menu : MenuHandle;
  47.                                     top, left, popUpItem : integer) : longint;
  48.     INLINE
  49.         $A80B;
  50.  
  51.  
  52.     PROCEDURE PlotDoubleIcon (theIcon : handle;
  53.                                     State : integer;
  54.                                     dstSquare : rect);
  55.  
  56.         VAR
  57.             srcSquare : rect;
  58.             data, mask, destBitMap, scratchBitMap : bitmap;
  59.             theGrafPort : GrafPtr;
  60.             LightGrayIcon, DarkGrayIcon : handle;
  61.  
  62.     BEGIN
  63.         IF (theIcon <> NIL) THEN
  64.             BEGIN
  65.                 SetRect(srcSquare, -16, -16, 16, 16);
  66.  
  67.                 data.rowBytes := 4;
  68.                 data.baseAddr := ptr(theIcon^);
  69.                 data.bounds := srcSquare;
  70.  
  71.                 mask.rowBytes := 4;
  72.                 mask.baseAddr := ptr(ord4(theIcon^) + 128);
  73.                 mask.bounds := srcSquare;
  74.  
  75.                 GetPort(theGrafPort);
  76.                 destBitMap := theGrafPort^.portbits;
  77.                 CASE state OF
  78.                     RestState : 
  79.                         BEGIN
  80.                             CopyBits(mask, destBitMap, srcSquare, dstSquare, srcBic, NIL);
  81.                             CopyBits(data, destBitMap, srcSquare, dstSquare, srcOr, NIL);
  82.                         END;
  83.                     SelectState : 
  84.                         BEGIN
  85. { old finder : }
  86.                             CopyBits(mask, destBitMap, srcSquare, dstSquare, srcBic, NIL);
  87.                             CopyBits(data, destBitMap, srcSquare, dstSquare, srcOr, NIL);
  88.                             CopyBits(mask, destBitMap, srcSquare, dstSquare, srcXOr, NIL);
  89. { new finder would be : }
  90. {CopyBits(mask, destBitMap, srcSquare, dstSquare, srcOr, nil);}
  91. {CopyBits(data, destBitMap, srcSquare, dstSquare, srcBic, nil);}
  92.                         END;
  93.                     OpenState : 
  94.                         BEGIN
  95.                             WITH scratchBitMap DO
  96.                                 BEGIN
  97.                                     LightGrayIcon := GetIcon(128);
  98.                                     BaseAddr := LightGrayIcon^;
  99.                                     bounds := srcSquare;
  100.                                     Rowbytes := 4;
  101.                                 END;
  102.                             CopyBits(mask, destBitMap, srcSquare, dstSquare, srcBic, NIL);
  103.                             CopyMask(scratchBitMap, mask, destBitMap, srcSquare, srcSquare, dstSquare);
  104.                         END;
  105.                     SelectOpenState : 
  106.                         BEGIN
  107.                             WITH scratchBitMap DO
  108.                                 BEGIN
  109.                                     DarkGrayIcon := GetIcon(129);
  110.                                     BaseAddr := DarkGrayIcon^;
  111.                                     bounds := srcSquare;
  112.                                     Rowbytes := 4;
  113.                                 END;
  114.                             CopyBits(mask, destBitMap, srcSquare, dstSquare, srcBic, NIL);
  115.                             CopyMask(scratchBitMap, mask, destBitMap, srcSquare, srcSquare, dstSquare);
  116.                         END;
  117.                     OTHERWISE
  118.                 END;
  119.             END
  120.     END;                { of PlotDoubleIcon }
  121.  
  122. { ***************************************************** }
  123.  
  124.     FUNCTION distance (startPt, endPt : point) : integer;
  125.     BEGIN
  126.         distance := abs(startPt.h - endPt.h) + abs(startPt.v - endPt.v);
  127.     END;
  128.  
  129.     FUNCTION InsideIcon (myPoint : point;
  130.                                     IconCenter : point;
  131.                                     myIcon : handle) : boolean;
  132.         VAR
  133.             bitOffset : longint;
  134.             scratchMap, dataMap, maskMap, sensitiveMap : bitmap;
  135.             square : rect;
  136.             x, y : integer;
  137.         LABEL
  138.             1;
  139.     BEGIN
  140.         HLock(myIcon);
  141.         SetRect(square, 0, 0, 32, 32);
  142.         WITH scratchMap DO
  143.             BEGIN
  144.                 bounds := square;
  145.                 BaseAddr := NewPtr(128);
  146.                 IF MemError <> NoErr THEN
  147.                     GOTO 1;
  148.                 RowBytes := 4;
  149.             END;
  150.         WITH sensitiveMap DO
  151.             BEGIN
  152.                 bounds := square;
  153.                 BaseAddr := NewPtr(128);
  154.                 IF MemError <> NoErr THEN
  155.                     GOTO 1;
  156.                 RowBytes := 4;
  157.             END;
  158.         WITH dataMap DO
  159.             BEGIN
  160.                 bounds := square;
  161.                 BaseAddr := myIcon^;
  162.                 RowBytes := 4;
  163.             END;
  164.         WITH maskMap DO
  165.             BEGIN
  166.                 bounds := square;
  167.                 BaseAddr := Ptr(ord4(myIcon^) + 128);
  168.                 RowBytes := 4;
  169.             END;
  170.         CopyBits(maskMap, scratchMap, square, square, srcCopy, NIL);
  171.         CopyBits(dataMap, scratchMap, square, square, srcOr, NIL);
  172.         CalcMask(scratchMap.baseAddr, sensitiveMap.baseAddr, 4, 4, 32, 2);
  173.         x := myPoint.h - IconCenter.h + 16;
  174.         y := myPoint.v - IconCenter.v + 16;
  175.         IF NOT ((x IN [0..31]) AND (y IN [0..31])) THEN
  176.             InsideIcon := false
  177.         ELSE
  178.             BEGIN
  179.                 bitOffset := x + 32 * y;
  180.                 InsideIcon := BitTst(sensitiveMap.baseAddr, bitOffset);
  181.             END;
  182.         HUnLock(myIcon);
  183.         DisposPtr(scratchMap.baseAddr);
  184.         DisposPtr(sensitiveMap.baseAddr);
  185. 1 :
  186.         IF MemError <> NoErr THEN
  187.             InsideIcon := false;
  188.     END;
  189.  
  190.  
  191.     FUNCTION DoubleClick (theControl : ControlHandle;
  192.                                     startPt : point;
  193.                                     startTime : longint;
  194.                                     VarCode : integer;
  195.                                     bounds : rect;
  196.                                     VAR IconCenter : point) : boolean;
  197.         VAR
  198.             mouse : point;
  199.             t : longint;
  200.             d : integer;
  201.             theEvent : EventRecord;
  202.             DoubleClicked : boolean;
  203.  
  204.         PROCEDURE DragSquare (startPt : point;
  205.                                         VAR IconCenter : point);
  206.             VAR
  207.                 oldFrame, frame, bounds : rect;
  208.                 delta, mouse : point;
  209.                 theGrafPort : GrafPtr;
  210.                 grayPattern : pattern;
  211.                 theTrash : ControlHandle;
  212.  
  213.             PROCEDURE HighLightTrash (mouse : point);
  214.                 VAR
  215.                     where : integer;
  216.                     IconCenter : point;
  217.                     OverFlownControl : ControlHandle;
  218.             BEGIN
  219.                 where := FindControl(mouse, FrontWindow, OverFlownControl);
  220.                 HLock(GetResource('CDEF', 128));
  221.                 FrameRect(oldFrame);
  222.                 IF theTrash <> OverFlownControl THEN
  223. { the control the mouse overflyes is no more "theTrash" }
  224.                     BEGIN
  225.                         IF theTrash <> NIL THEN
  226. { the mouse has ended overflying a trash }
  227.                             BEGIN
  228.                                 SetCtlValue(theTrash, GetCtlValue(theTrash) - 1);
  229.                                 HLock(theTrash^^.ContrlDefProc);
  230.                             END;
  231.                         IF (OverFlownControl <> NIL) THEN
  232.                             IF BitTst(pointer(OverFlownControl^), varCodeBase - trashBit) AND (theControl <> OverFlownControl) THEN
  233. { the mouse begins overflying a trash }
  234.                                 BEGIN
  235.                                     SetCtlValue(OverFlownControl, GetCtlValue(OverFlownControl) + 1);
  236.                                     HLock(OverFlownControl^^.ContrlDefProc);
  237.                                     theTrash := OverFlownControl;
  238.                                 END
  239.                             ELSE
  240. { the mouse overflies something else than a trash }
  241.                                 theTrash := NIL
  242.                         ELSE
  243. { the mouse doesn't overfly anything }
  244.                             theTrash := NIL;
  245.                     END;
  246.             END;
  247.  
  248.         BEGIN                    { DragSquare }
  249.             theTrash := NIL;
  250.             StuffHex(@grayPattern, '55AA55AA55AA55AA');
  251.             GetPort(theGrafPort);
  252.             bounds := theGrafPort^.PortRect;
  253.             InSetRect(bounds, 16, 16);
  254.             delta := IconCenter;
  255.             SubPt(startPt, delta);
  256.             PenMode(PatXor);
  257.             WITH IconCenter DO
  258.                 SetRect(oldFrame, h - 16, v - 16, h + 16, v + 16);
  259.             PenPat(grayPattern);
  260.             FrameRect(oldFrame);
  261. { instead of the surrounding square }
  262. { we could also drag the icon's data or mask frame }
  263.             REPEAT
  264.                 GetMouse(mouse);
  265.                 IconCenter := mouse;
  266.                 AddPt(delta, IconCenter);
  267.                 WITH IconCenter, bounds DO
  268.                     BEGIN
  269.                         IF h < left THEN
  270.                             h := left;
  271.                         IF h > right - 1 THEN
  272.                             h := right - 1;
  273.                         IF v < top THEN
  274.                             v := top;
  275.                         IF v > bottom - 1 THEN
  276.                             v := bottom - 1;
  277.                     END;
  278.                 WITH IconCenter DO
  279.                     SetRect(frame, h - 16, v - 16, h + 16, v + 16);
  280.                 IF NOT EqualRect(oldFrame, frame) THEN
  281.                     BEGIN
  282.                         HighLightTrash(mouse);
  283.                         FrameRect(frame);
  284.                         oldFrame := frame;
  285.                     END;
  286.             UNTIL NOT WaitMouseUp;
  287.             FrameRect(frame);
  288.             PenNormal;
  289.         END;
  290.  
  291.     BEGIN                { DoubleClick }
  292.         DoubleClicked := false;
  293.         BEGIN
  294. { if doubleClickable or movable : }
  295.             IF (BitTst(@varCode, integerLength - doubleClickableBit)) OR (BitTst(@varCode, integerLength - movableBit)) THEN
  296.                 REPEAT
  297.                     GetMouse(mouse);
  298.                     d := distance(startPt, mouse);
  299.                 UNTIL (NOT WaitMouseUp OR (d > 3));
  300.             IF (d > 3) AND BitTst(@varCode, integerLength - movableBit) THEN
  301.                 DragSquare(startPt, IconCenter)
  302.             ELSE IF BitTst(@varCode, integerLength - doubleClickableBit) THEN
  303.                 REPEAT
  304.                     GetMouse(mouse);
  305.                     d := distance(startPt, mouse);
  306.                     t := TickCount - startTime;
  307.                     IF GetNextEvent(MDownMask, theEvent) THEN
  308.                         DoubleClicked := true;
  309.                 UNTIL DoubleClicked OR (d > 3) OR (t > GetDblTime);
  310.             DoubleClick := DoubleClicked;
  311.         END;
  312.     END;
  313.  
  314. { ***************************************************** }
  315.  
  316.     FUNCTION Main;
  317.  
  318.         VAR
  319. { color under the title : }
  320.             whitePattern : pattern;
  321.  
  322.         PROCEDURE DoDrawCntl;
  323.             VAR
  324.                 IconCenter, TextCenter : point;
  325.                 State, theLength, theHalfLength : integer;
  326.                 TextFrame, IconFrame : rect;
  327.                 myDataHandle : DataHandle;
  328.         BEGIN
  329.             State := GetCtlValue(theControl);
  330.  
  331. { MenuReturnState is drawn like RestState, ThrownAwayState is not re-drawn : }
  332.  
  333.             IF State = MenuReturnState THEN
  334.                 State := RestState;
  335.             IF ((State IN [RestState..SelectOpenState]) AND (theControl^^.ContrlVis <> 0)) THEN
  336.                 BEGIN
  337.                     HLock(handle(theControl));
  338.                     WITH theControl^^ DO
  339.                         BEGIN
  340.                             TextFont(geneva);
  341.                             TextFace([]);
  342.                             TextMode(SrcOr);
  343.                             TextSize(9);
  344.                             theLength := StringWidth(contrlTitle);
  345.                             IF theLength < 32 THEN
  346.                                 theHalfLength := 16
  347.                             ELSE
  348.                                 theHalfLength := theLength DIV 2;
  349.                             WITH ContrlRect DO
  350.                                 SetPt(IconCenter, (right + left) DIV 2, (bottom - 12 + top) DIV 2);
  351.  
  352. { recalculate the rectangle surrounding the whole control : }
  353.  
  354.                             WITH IconCenter, ContrlRect DO
  355.                                 BEGIN
  356.                                     left := h - theHalfLength;
  357.                                     top := v - 16;
  358.                                     right := h + theHalfLength;
  359.                                     bottom := v + 16 + 12;
  360.                                 END;
  361.  
  362.                             WITH IconCenter, IconFrame DO
  363.                                 BEGIN
  364.                                     left := h - 16;
  365.                                     top := v - 16;
  366.                                     right := h + 16;
  367.                                     bottom := v + 16;
  368.                                 END;
  369.  
  370. { draw the icon-control's title : }
  371.  
  372.                             WITH IconCenter DO
  373.                                 SetPt(TextCenter, h, v + 26);
  374.                             WITH TextCenter DO
  375.                                 SetRect(TextFrame, h - theLength DIV 2, v - 10, h + theLength DIV 2, v + 2);
  376.                             StuffHex(@whitePattern, '0000000000000000');
  377.                             FillRect(TextFrame, whitePattern);
  378.                             WITH TextCenter DO
  379.                                 MoveTo(h - theLength DIV 2, v);
  380.                             DrawString(contrlTitle);
  381.  
  382. { draw the icon : }
  383.  
  384.                             myDataHandle := DataHandle(ContrlData);
  385.                             HLock(myDataHandle^^.theIcon);
  386.                             PlotDoubleIcon(myDataHandle^^.theIcon, State, IconFrame);
  387.                             HUnLock(myDataHandle^^.theIcon);
  388.  
  389.                         END;
  390.                     HUnLock(handle(theControl));
  391.                 END;
  392.             Main := 0;
  393.         END;
  394.  
  395.         PROCEDURE DoTestCntl;
  396.             VAR
  397.                 IconCenter, mouse : point;
  398.                 myDataHandle : DataHandle;
  399.         BEGIN
  400.             HLock(handle(theControl));
  401.             WITH theControl^^ DO
  402.                 BEGIN
  403.                     SetPt(mouse, LoWord(param), HiWord(param));
  404.                     IF PtInRect(mouse, ContrlRect) THEN
  405.                         BEGIN
  406.                             WITH ContrlRect DO
  407.                                 SetPt(IconCenter, (right + left) DIV 2, (bottom - 12 + top) DIV 2);
  408.                             myDataHandle := DataHandle(ContrlData);
  409.                             Main := ord4(InsideIcon(mouse, IconCenter, myDataHandle^^.theIcon));
  410.                         END
  411.                     ELSE
  412.                         main := 0;
  413.                 END;
  414.             HUnLock(handle(theControl));
  415.         END;
  416.  
  417.         PROCEDURE DoCalcCRgns;
  418.             CONST
  419.                 Lo3Bytes = $00FFFFFF;
  420.             VAR
  421.                 IconFrame, TextFrame : rect;
  422.                 theTitle : Str255;
  423.                 theLength, theHalfLength, halfWay : integer;
  424.         BEGIN
  425.             GetCTitle(theControl, theTitle);
  426.             theLength := StringWidth(theTitle);
  427.             theHalfLength := theLength DIV 2;
  428.             param := BitAnd(param, Lo3Bytes);
  429.             IconFrame := theControl^^.ContrlRect;
  430.             WITH IconFrame DO
  431.                 BEGIN
  432.                     bottom := bottom - 12;
  433.                     halfWay := (right + left) DIV 2;
  434.                     left := halfWay - 16;
  435.                     right := halfWay + 16;
  436.                     SetRect(TextFrame, halfWay - theHalfLength, bottom, halfWay + theHalfLength, bottom + 12);
  437.                 END;
  438.             OpenRgn;
  439.             FrameRect(IconFrame);
  440.             FrameRect(TextFrame);
  441.             CloseRgn(RgnHandle(param));
  442.             Main := 0;
  443.         END;
  444.  
  445.         PROCEDURE DeselectExcept (theControl : ControlHandle);
  446.             VAR
  447.                 myWindowPeek : WindowPeek;
  448.                 aControl : ControlHandle;
  449.         BEGIN
  450.             myWindowPeek := WindowPeek(theControl^^.ContrlOwner);
  451.             aControl := myWindowPeek^.ControlList;
  452.             WHILE aControl <> NIL DO
  453.                 BEGIN
  454.                     IF (aControl <> theControl) THEN
  455.                         BEGIN
  456.                             IF (GetCtlValue(aControl) = 1) THEN
  457.                                 BEGIN
  458.                                     SetCtlValue(aControl, 0);
  459.                                     HLock(aControl^^.ContrlDefProc);
  460.                                 END
  461.                             ELSE IF (GetCtlValue(aControl) = 3) THEN
  462.                                 BEGIN
  463.                                     SetCtlValue(aControl, 2);
  464.                                     HLock(aControl^^.ContrlDefProc);
  465.                                 END
  466.                         END;
  467.                     aControl := aControl^^.nextControl;
  468.                 END;
  469.         END;
  470.  
  471.         PROCEDURE DoAutoTrack;
  472.             VAR
  473.                 SavedClip, UpDateRegion : RgnHandle;
  474.                 PopUpMenuHdl : MenuHandle;
  475. {MDEFPtr : Ptr;{ for debugging only }
  476.                 theTitle : Str255;
  477.                 choosenItem, dummy : longint;
  478.                 halfWay, theHalfLength, where : integer;
  479.                 oldCenter, IconCenter, mouse, MenuTitleCenter : point;
  480.                 theGrafPort : GrafPtr;
  481.                 theTrash : ControlHandle;
  482.                 myDataHandle : DataHandle;
  483.                 isAMenu, isDoubleClickable, isMovable : boolean;
  484.         BEGIN
  485.             isAMenu := BitTst(@varCode, integerLength - MenuBit);
  486.             isDoubleClickable := BitTst(@varCode, integerLength - DoubleClickableBit);
  487.             isMovable := BitTst(@varCode, integerLength - MovableBit);
  488.             IF isAMenu OR isDoubleClickable OR isMovable THEN
  489.                 BEGIN
  490.                     IF GetCtlValue(theControl) = OpenState THEN
  491.                         SetCtlValue(theControl, SelectOpenState)
  492.                     ELSE IF GetCtlValue(theControl) = RestState THEN
  493.                         SetCtlValue(theControl, SelectState);
  494.                     HLock(theControl^^.ContrlDefProc);
  495.                 END;
  496.             DeselectExcept(theControl);
  497.             GetMouse(mouse);
  498.             WITH theControl^^.ContrlRect DO
  499.                 SetPt(IconCenter, (right + left) DIV 2, (bottom - 12 + top) DIV 2);
  500.             oldCenter := IconCenter;
  501.             GetPort(theGrafPort);
  502.  
  503. { 1° : DOUBLE-CLICK }
  504.  
  505.             IF DoubleClick(theControl, mouse, TickCount, varCode, theGrafPort^.PortRect, IconCenter) THEN
  506.                 BEGIN
  507.                     SetCtlValue(theControl, SelectOpenState);
  508.                     HLock(theControl^^.ContrlDefProc);
  509.                 END
  510.  
  511. { 2° : NO DRAGGING }
  512.  
  513.             ELSE IF EqualPt(oldCenter, IconCenter) THEN
  514.                 BEGIN
  515.  
  516. { 2.1 : POPUPMENU }
  517.  
  518.                     IF isAMenu THEN
  519.                         BEGIN
  520.                             myDataHandle := DataHandle(theControl^^.ContrlData);
  521.                             PopUpMenuHdl := myDataHandle^^.theMenu;
  522.  
  523.                             WITH theControl^^.ContrlRect, MenuTitleCenter DO
  524.                                 BEGIN
  525.                                     h := (left + right) DIV 2;
  526.                                     v := (top + bottom) DIV 2;
  527.                                 END;
  528.                             LocalToGlobal(MenuTitleCenter);
  529.                             WITH MenuTitleCenter DO
  530.                                 choosenItem := PopUpMenuSelect(PopUpMenuHdl, h, v, 0);
  531. { re-draw the control as in RestState : }
  532.                             SetCtlValue(theControl, MenuReturnState);
  533.                             HLock(theControl^^.ContrlDefProc);
  534.                             SetCRefCon(theControl, choosenItem);
  535.                         END
  536.  
  537. { 2.2 : SIMPLE SELECTION OF A DOUBLE-CLICKABLE CONTROL }
  538.  
  539. { the Control is already highlighted in the "SelectState" }
  540.                 END
  541.  
  542. { 3° : DRAGGING }
  543.  
  544.             ELSE
  545.                 BEGIN
  546.                     GetMouse(mouse);
  547.                     where := FindControl(mouse, FrontWindow, theTrash);
  548.                     HLock(GetResource('CDEF', 128));
  549.                     IF (theTrash <> NIL) THEN
  550.  
  551. { 3.1 : THROWING THE CONTROL AWAY IN A TRASH }
  552.  
  553.                         IF BitTst(pointer(theTrash^), varCodeBase - trashBit) AND (theTrash <> theControl) THEN
  554.                             BEGIN
  555. { return "theTrash" in CRefCon }
  556. { without re-drawing it }
  557.                                 SetCRefCon(theControl, ord(theTrash));
  558.                                 SetCtlValue(theControl, ThrownAwayState);
  559.                                 HLock(theControl^^.ContrlDefProc);
  560.                             END;
  561.  
  562. { 3.2 : MOVING }
  563.  
  564.                     IF (GetCtlValue(theControl) <> ThrownAwayState) THEN
  565.                         BEGIN
  566.                             WITH theControl^^.ContrlRect DO
  567.                                 theHalfLength := (right - left) DIV 2;
  568.  
  569. { move the control without showing it : }
  570.  
  571.                             HideControl(theControl);
  572.                             HLock(theControl^^.ContrlDefProc);
  573.                             WITH IconCenter DO
  574.                                 MoveControl(theControl, h - theHalfLength, v - 16);
  575.                             HLock(theControl^^.ContrlDefProc);
  576.                             theControl^^.ContrlValue := RestState;
  577.  
  578. { the UpDate mechanism will do the re-drawing }
  579. { in such a way it lets the prealably hidden controls appear : }
  580.  
  581.                             SavedClip := NewRgn;
  582.                             GetClip(SavedClip);
  583.                             SetEmptyRgn(theGrafPort^.ClipRgn);
  584.                             ShowControl(theControl);
  585.                             HLock(theControl^^.ContrlDefProc);
  586.                             SetClip(SavedClip);
  587. { re-use an initialised region for another purpose : }
  588.                             UpDateRegion := SavedClip;
  589. { send the CalCRgns message to calculate UpDateRegion : }
  590.                             dummy := Main(0, theControl, calcCRgns, ord4(UpDateRegion));
  591.                             EraseRgn(UpDateRegion);
  592.                             InValRgn(UpDateRegion);
  593.                             DisposeRgn(UpDateRegion);
  594.                         END;
  595.                 END;
  596.             Main := 0;
  597.         END;
  598.  
  599.         PROCEDURE DoInitCntl;
  600.             VAR
  601.                 myDataHandle : DataHandle;
  602.                 theTitle : Str255;
  603.         BEGIN
  604.             GetCTitle(theControl, theTitle);
  605.             myDataHandle := DataHandle(NewHandle(sizeof(DataRecord)));
  606.             HLock(handle(myDataHandle));
  607.             WITH myDataHandle^^ DO
  608.                 BEGIN
  609.                     theIcon := GetNamedResource('ICN#', theTitle);
  610. { Initialisation should have called "GetMenu" : }
  611.                     theMenu := MenuHandle(GetNamedResource('MENU', theTitle));
  612.                 END;
  613.             HUnLock(handle(myDataHandle));
  614.             WITH theControl^^ DO
  615.                 BEGIN
  616.                     ContrlAction := pointer(-1);
  617.                     ContrlData := handle(myDataHandle);
  618.                 END;
  619.         END;
  620.  
  621.         PROCEDURE DoDispCntl;
  622.         BEGIN
  623.             DisposHandle(theControl^^.ContrlData);
  624.         END;
  625.  
  626.     BEGIN            { Main procedure }
  627.         CASE message OF
  628.             drawCntl : 
  629.                 DoDrawCntl;
  630.             testCntl : 
  631.                 DoTestCntl;
  632.             calcCRgns : 
  633.                 DoCalcCRgns;
  634.             initCntl : 
  635.                 DoInitCntl;
  636.             dispCntl : 
  637.                 DoDispCntl;
  638.             dragCntl :    { for a smoother interface }
  639.                 BEGIN
  640.                     DoAutoTrack;
  641.                     Main := 1;    { to tell the Control Manager not to use the standard method }
  642.                 END;
  643.             autoTrack : 
  644.                 DoAutoTrack;
  645.             OTHERWISE        { dragCntl, posCntl , thumbCntl }
  646.                 main := 0;
  647.         END;
  648.     END;
  649.  
  650. END.